home *** CD-ROM | disk | FTP | other *** search
- solution for Kwazy Webbit's PacMe Crackme
- solved By Nuno1 on 24 july 1999
- any comments can be sent to nuno_2@hotmail.com
-
-
- Information :
- Cracker : Nuno1
- Date : 24 july 1999
- Level : 4
- Protection : KeyFile Missing , Simple Encryption Method.
-
- Tools used :
- - SoftIce
- - Borland C for Keyfile Generator.
-
- Hey Crackers !
-
- this is one of the cracks i really enjoy cracking. not an easy one but really not hard one.
-
- -- Information --
-
- when you run the program , you see an UNREGISTERD label , and also a CHECK Button.
- you cant write on the UNREGISTERD label . just a check button left ;)
-
- -- The Crack --
-
- because of it , you can understand that its not a serial / code crack .
- let see if its a KeyFile crack ..
-
- bpx on CreateFileA to break if a file is open .
-
- press the check button .. yep .. it jump to the trap .. ;)
-
- CreateFileA function gets on EDX the name of the file .
- lets do "d edx" .. you can see a strange filename called "KwazyWeb.bit" .
- ok ... copy your autoexec.bat to this directory and rename it KwazyWeb.bit.
- lets press the check button again ..
- ok .. now press F12 and u will see Eax return a number (if it was -1 it means not exists)
- so we made the first step ..
- lets contine .. you will see this code :
-
- :004016D9 E81C010000 KERNEL32.CreateFileA
- :004016DE 83F8FF cmp eax, FFFFFFFF <- check if the KwazyWeb.bit exist
- :004016E1 7464 je 00401747
- :004016E3 A344344000 mov dword ptr [00403444], eax <-moving the handle of the file
- :004016E8 6A00 push 00000000
- :004016EA 6848344000 push 00403448 <-pushing a variable
- :004016EF 6A01 push 00000001 <-pushing 1
- :004016F1 68FA344000 push 004034FA <-pushing another variable.
- :004016F6 FF3544344000 push dword ptr [00403444] <-and the handle of the file
- :004016FC E811010000 KERNEL32.ReadFile <-call the readfile.
-
- ok , whats really going on here.
-
- the ReadFile function get some params .. all we really cares are the PUSH 00000001 and
- PUSH 004034FA .. the PUSH 1 is really the length to read from the file.
- the push 4034fa is where to copy the read chars..
-
- ok , so he read one byte to 4034fa.
- look at 4034fa after Readfile you will notice the first char that in your file.
-
- lets contine :
-
- :00401701 0FB605FA344000 movzx eax, byte ptr [004034FA] <- eax get the first char
- :00401708 85C0 test eax, eax <- check if it 0
- :0040170A 743B je 00401747
- :0040170C 6A00 push 00000000
- :0040170E 6848344000 push 00403448
- :00401713 50 push eax <- push the first char
- :00401714 6888324000 push 00403288 <- another variable
- :00401719 FF3544344000 push dword ptr [00403444] <- the handle of the file.
- :0040171F E8EE000000 KERNEL32.ReadFile <- calling ReadFile
-
- ok .. so now he called readfile again but this time he used the first char as the new
- length to read .. is it a len of any string ? maybe but we dont care yet ;).
-
- after that there is a call .. let see what is this call :
-
- :00401000 33C0 xor eax, eax <- eax = 0
- :00401002 33D2 xor edx, edx <- edx = 0
- :00401004 33C9 xor ecx, ecx <- ecx = 0
- :00401006 8A0DFA344000 mov cl, byte ptr [004034FA] <- cl = length
- :0040100C BE88324000 mov esi, 00403288 <- esi = the new chars we read
- :00401011 AC lodsb <- read a char from esi and
- <- and esi + 1
- :00401012 03D0 add edx, eax <- edx + char
- :00401014 E2FB loop 00401011 <- loop length times
- :00401016 8815FB344000 mov byte ptr [004034FB], dl <- take the low byte of dx and
- <- keep it in 4034fb
- :0040101C C3 ret
-
- as we can understand .. this is just calculate the sum of the characters we read and keep
- it in a variable (4034fb)
-
- lets return to after the call :
-
- :00401729 6A00 push 00000000
- :0040172B 6848344000 push 00403448
- :00401730 6A12 push 00000012 <- push 12
- :00401732 68E8344000 push 004034E8 <- push it
- :00401737 FF3544344000 push dword ptr [00403444] <- push our file handle
- :0040173D E8D0000000 Call KERNEL32.ReadFile <- readfile
- :00401742 E882F9FFFF call 004010C9 <- ??
- :00401747 FF3544344000 push dword ptr [00403444] <- file handle
- :0040174D E8A2000000 Call KERNEL32.CloseHandle <- closefile
-
- so we see now that it push 12h as the length param , so he take 12h next characters.
- after the strange call he close the file .. so maybe all the answers is in this call.
-
- let check it out :
-
- :004010C9 55 push ebp
- :004010CA 8BEC mov ebp, esp
- :004010CC 83C4FC add esp, FFFFFFFC
- :004010CF 6865334000 push 00403365 <- looks like a strange looking maze !?
- :004010D4 68BC314000 push 004031BC <- this is the same as above !
- :004010D9 E83A070000 Call KERNEL32.lstrcpyA <- copy to 403365 the 4031bc string
- :004010DE C70584314000CC314000 mov dword ptr [00403184], 004031CC
- :004010E8 E830FFFFFF call 0040101D <-another call !
-
-
- so he copy a strange looking maze and then calling another function .. let see what is this function
-
- :0040101D 8A15FB344000 mov dl, byte ptr [004034FB] <- the total we calculate before
- :00401023 B912000000 mov ecx, 00000012 <- ecx = 12 ?
- :00401028 B8E8344000 mov eax, 004034E8 <- eax = 12 characters we read
- :0040102D 3010 xor byte ptr [eax], dl <- xor the new characters we read
- <- with the lowbyte of the total we calc.
- :0040102F 40 inc eax <- go to the next char.
- :00401030 E2FB loop 0040102D <- loop 12h times.
- :00401032 C3 ret
-
- mmmm .. so now we can see he take the 12 numbers we read last and xor it with the lowbyte
- total of characters we read before.
-
-
- let see now whats happend (returning from the call);
-
-
- :004010ED C645FE00 mov [ebp-02], 00 <-ebp-2 = 0
- :004010F1 33C0 xor eax, eax <-eax=0
- :004010F3 33C9 xor ecx, ecx <-ecx=0
- :004010F5 C645FF08 mov [ebp-01], 08 <-ebp-1 = 8
- :004010F9 806DFF02 sub byte ptr [ebp-01], 02 <-ebp-1 - 2
- :004010FD 0FB64DFE movzx ecx, byte ptr [ebp-02] <-ecx = ebp-2
- :00401101 81C1E8344000 add ecx, 004034E8 <-ecx=ecx + the start of the xored numbers
- :00401107 8A01 mov al, byte ptr [ecx] <-al = xored number
- :00401109 8A4DFF mov cl, byte ptr [ebp-01] <-cl = ebp -1
- :0040110C D2E8 shr al, cl <-al >> cl ???
- :0040110E 2403 and al, 03 <-al & 3 (11b)
- :00401110 E81EFFFFFF call 00401033 <-another call
- :00401115 85C0 test eax, eax <-eax = 0 ? jmp
- :00401117 7411 je 0040112A
- :00401119 0FB655FF movzx edx, byte ptr [ebp-01] <-edx = ebp-1
- :0040111D 85D2 test edx, edx <-edx = 0 ?
- :0040111F 75D8 jne 004010F9 <-if not jmp
- :00401121 FE45FE inc [ebp-02] <-if yes, inc ebp2
- :00401124 807DFE12 cmp byte ptr [ebp-02], 12 <-ebp-2 <> 12 ??
- :00401128 75CB jne 004010F5 <-then jump
- :0040112A C9 leave <-else finish
- :0040112B C3 ret
-
- ok , lets start to make it understanding (even before the call we didnt yet examine.
- ebp-2 looks like a counter of 12h because it been increased every time and exit when = 12
- ebp-1 = 6 at start (notice the first sub of it with 2) and allways dec by 2 and it also a
- counter , because it test when it 0 .
- so we first can understand this is loop in a loop.
- we call the first loop outloop and the second loop inloop.
-
- in the inloop he takes one xored number shl it with 6 and keep the two first bits and then
- the same with with 4 , 2 and 0. then he exit the loop. the outloop go increase ECX and
- thats make the inloop get the next xored number. all this goes until the outloop pass 12h
- times.
-
- in other words :
-
- every number from the xored numbers are 4 numbers that are from 0 to 3 (00b,01b,10b and 11b)
- each two bits in the byte represent a number from 0-3.
- so this is 04h * 12h numbers to pass.
-
- now.. let see what the other call do ..
-
- :00401033 55 push ebp
- :00401034 8BEC mov ebp, esp
- :00401036 83C4F8 add esp, FFFFFFF8
- :00401039 8B1584314000 mov edx, dword ptr [00403184] <- edx = the place on the MAZE
- <- that the char "C" found
- :0040103F 8955FC mov dword ptr [ebp-04], edx <-ebp-4 = "C" char
- :00401042 0AC0 or al, al <- or al,al
- :00401044 7509 jne 0040104F <- jmp if al <> 0
- :00401046 832D8431400010 sub dword ptr [00403184], 00000010 <-if 0 add to the pointer
- <-"C" place 10
- :0040104D EB1F jmp 0040106E <- jmp 40106e
- :0040104F 3C01 cmp al, 01 <- if al = 1
- :00401051 7508 jne 0040105B <- if not go to 40105b
- :00401053 FF0584314000 inc dword ptr [00403184] <- add to the pointer of "C" 1
- :00401059 EB13 jmp 0040106E <- jmp 40106e
- :0040105B 3C02 cmp al, 02 <- al,2
- :0040105D 7509 jne 00401068 <- if not go to 401068
- :0040105F 83058431400010 add dword ptr [00403184], 00000010 <- add to the ptr of "C" 10
- :00401066 EB06 jmp 0040106E <- jmp
- :00401068 FF0D84314000 dec dword ptr [00403184] <- if not 0,1,2 (means 3)
- <- subthe ptr of "C" 1
- :0040106E 8B1584314000 mov edx, dword ptr [00403184] <- here all the jmp come to.
- <- edx = new MAZE place
- :00401074 8A02 mov al, byte ptr [edx] <- al = MAZE
- :00401076 3C2A cmp al, 2A <- al = '*'
- :00401078 7506 jne 00401080 <- if not jmp
- :0040107A 33C0 xor eax, eax <- if yes eax=0
- :0040107C C9 leave <- and leave
- :0040107D C3 ret
- :0040107E EB33 jmp 004010B3
- :00401080 3C58 cmp al, 58 <- if not "*" is it "X"
- :00401082 752F jne 004010B3
-
- i will cut if it IS 58 and jump to if its not 58.
-
- :004010B3 8B1584314000 mov edx, dword ptr [00403184] <- edx = maze place.
- :004010B9 C60243 mov byte ptr [edx], 43 <- maze place = "C"
- :004010BC 8B55FC mov edx, dword ptr [ebp-04] <- old maze place
- :004010BF C60220 mov byte ptr [edx], 20 <- maze = " "
- :004010C2 B801000000 mov eax, 00000001 <- eax = 1 and exit.
- :004010C7 C9 leave
- :004010C8 C3 ret
-
- ok .. lets start to understand this maze thing
-
- if you will look at EDX whe it get [403184] you will see this maze :
-
- ****************
- C* * ****
- * **** * *
- * ********** *
- * * * *
- * **** * * ***
- * * * *******
- * *** * *
- * *** ** *** *
- **** *X *
- ****************
-
- you can notice the C and X letters . the place we get into start in the C char.
-
- you can count , the number of * at the first line are 16 (10h) .
-
- ok now let see what the function does really.
-
- all it does is check if the number he got is 0,1,2,3.
- if 0 , he sub 10h from the maze place that will bring us in the same X-coord in the maze
- but one line up (in the Y-Coord).
- if 1 , he increase the maze place.. it means we moved left.
- so every number really get us to a diffrent position.. (0,1,2,3 is the number of postions !)
-
- so here is the moves :
- 0 - up
- 1 - right
- 2 - down
- 3 - left
-
- ok so he place it in the new place and check if there is a "*" in it ..
- if there is , he return to the called fuction 0. if its not he return 1.
- if its 'X' he jump to a place that said SUCCESS .... ha ! thats it ..
- we finish debugging it ... but what now ? what we need to do ?
-
- ok ... here it goes .
-
- as we now know the 12h numbers we pass are really a 12h * 4h moves of the maze .
- (you can check the numbers of moves in it you will notice its right ;) ).
- but the problem is that we cant just write the numbers in the file and let him read it
- because its xored with the total characters we read before ... and now we can also notice
- those characters are the registration Name !!
- so he XORED those 12h number with the total sum of the Registration Name !!
-
- this method is really called xored encyption , if you have the xored key you just have to
- xor the number with the key and you get the same number !
-
- so all we have to do (as i allready did) is to write a program that sum Registration name
- and have a table with all the steps we need to do , and start to xor it with the sum.
- keep all of this in the file and it will be cracked ;)
-
- as you can see , this is the maze soulotion (but with the real numbers for the move)
-
- C 011111 011
- 2 0 211 2111
- 2 10 2
- 21 3330 330 332
- 2 0 2 332
- 2 0111 2
- 32 0 32 01111
- 2 01 2 0 2
- 211 2111 332
-
- and in a better way to view it :
- 22212223221101
- 00111003330100
- 11111211011211
- 12233233033222
- 32211100111122
- 33
-
- just xor this with the total and you finished .. you are welcome to look at my source code.
-
- -- Notes --
-
- this was a fun crackme for me ... i hope there are more nice crackme like that ;)
-
- hope you learn somthing new ;)
-
- Nuno1 - Nuno2@hotmail.com
-
-
-